#pragma once
#include "Common.hpp"
#include "Socket.hpp"
#include "Connection.hpp"
#include "Channel.hpp"


using namespace mySocket;

class Listener : public Connection{
private:
    //默认的端口号
    const static int defaultport = 8080;

public:
    Listener(uint16_t port = defaultport)
        :_port(port),
        _listensock(std::make_shared<TcpSocket>())
    {
        _listensock->CreateServerTcpSocket(_port);
        //设置fd为非阻塞 -> 使用的ET模式的前置条件
        SetNoBlock(_listensock->GetFd());
        //还需要设置关注事件  ET模式 ：EPOLLET
        SetEvents(EPOLLIN | EPOLLET); //对于listensock来说，关注读事件即可！
    }

    ~Listener(){}

    //对读取进行重写 其余的不需要！
    virtual void Recver() override{
        //对于监听sockfd来说，所谓的读事件就是获取到新得链接
        //今天这里，使用的是ET模式，所以，需要循环的读取！
        //但是，ET模式，需要把对应的fd设置为非阻塞！ -> 设置   

        //1.此时就需要不断地获取新连接 -> while获取
        while(true){
            InetAddr client;
            int sockfd = _listensock->AcceptOrDie(&client);
            if(sockfd < 0){
                //此时小于0，真的是出错了吗？ 
                //如果是阻塞accept的话，那就是；但是今天这里是非阻塞！

                //如果单次轮询都没有收到新的连接，说明可以目前还没有新的连接来！
                if(sockfd == ACCEPT_DONE) break;
                else if(sockfd == ACCEPT_AGAIN) continue;
                //获取失败直接退出
                else break;
            }
            else{
                //一旦获取到一个新的连接，就需要做以下两件事情：
                //新的fd也是不能直接读取的！ -> 需要被epoll接管
                //在今天的代码中，fd是被封装的，普通fd是Channel

                //1.创建新的普通文件描述符类！
                std::shared_ptr<Connection> ch = std::make_shared<Channel>(sockfd, client);
                //2.在被接管前，得先知道这个fd关注的事件是什么？  -> 设置事件
                ch->SetEvents(EPOLLIN | EPOLLET);
                //3.加入内核管理 并且还要加入到Reactor的_connections进行管理

                //加入业务回调逻辑 ---TODO(需要说清楚这里的逻辑) 其实就是把服务绑在listener的基类，然后再一一拷贝给新连接即可
                if(_handler_conn != nullptr) ch->RegsiterHandler(_handler_conn);

                //这两步怎么做？ -> 通过基类的回调指针即可！ 
                //至此，新连接加入到了内核 和哈希，后序拿着新连接的fd索引哈希，然后通过注册的服务来进行操作即可！
                //不过，需要在服务启动前，把这个服务注册给Listener，这个是 main函数内做的事情！
                GetReactBackPtr()->AddConnection(ch);
            }
        }
    }

    virtual void Sender(){}
    virtual void Excepter(){}


    virtual int GetSockFd() override{return _listensock->GetFd();}
    
    virtual uint16_t GetPort() {return _port;}

private:
    uint16_t _port;
    std::shared_ptr<Socket> _listensock;
};